/*
 * Copyright (C) 2014 Eduardo Pereira Montenegro <epereiramontenegro@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.bambole.util;

import java.security.SecureRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import org.apache.commons.codec.binary.Base64;

/**
 *
 * @author Eduardo Pereira Montenegro <epereiramontenegro@gmail.com>
 */
public class PasswordUtil {

    private static final int iterations = 10 * 1024;
    private static final int saltLen = 32;
    private static final int desiredKeyLen = 256;

    public static String generateRandomPassword() {

        String upper = "QWERTYUIOPASDFGHJKLZXCVBNM";
        String lower = "qwertyuiopasdfghjklzxcvbnm";
        String number = "0123456789";
        String special = "@#$&";

        StringBuilder password = new StringBuilder();

        for (int i = 0; i < 3; i++) {
            password.append(upper.charAt((int) (Math.random() * 25)));
            password.append(lower.charAt((int) (Math.random() * 25)));
            password.append(number.charAt((int) (Math.random() * 9)));
            password.append(special.charAt((int) (Math.random() * 3)));
        }

        return password.toString();
    }

    public static boolean isPasswordFormatValid(String password) {

        Pattern pattern = Pattern.compile("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$&])(?=\\S+$).{8,12}$");

        Matcher matcher = pattern.matcher(password);

        return matcher.matches();
    }

    public static String getSaltedHashPassword(String password) throws Exception {

        byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen);

        return Base64.encodeBase64String(salt) + "$" + hash(password, salt);
    }

    public static boolean isInputPasswordValid(String password, String stored) throws Exception {

        String[] saltAndPass = stored.split("\\$");

        if (saltAndPass.length != 2) {
            return false;
        }

        String hashOfInput = hash(password, Base64.decodeBase64(saltAndPass[0]));

        return hashOfInput.equals(saltAndPass[1]);
    }

    private static String hash(String password, byte[] salt) throws Exception {

        if (password == null || password.isEmpty()) {
            throw new IllegalArgumentException("Empty passwords are not supported.");
        }

        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        SecretKey key = f.generateSecret(new PBEKeySpec(password.toCharArray(), salt, iterations, desiredKeyLen));

        return Base64.encodeBase64String(key.getEncoded());
    }

}
